package com.pignest.hotel.ui.room;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Div;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Vbox;

import com.pignest.framework.util.Log;
import com.pignest.hotel.beans.Booking;
import com.pignest.hotel.beans.BookingRoom;
import com.pignest.hotel.beans.Living;
import com.pignest.hotel.beans.Room;
import com.pignest.hotel.definition.BookingStatus;
import com.pignest.hotel.definition.RoomStatus;
import com.pignest.hotel.service.RoomService;
import com.pignest.hotel.spring.Services;
import com.pignest.hotel.util.UIUtils;

/**
 * 房态图
 * 
 * @author Jude
 */
public class RoomHistogram extends Vbox implements EventListener {
	private static final long serialVersionUID = 411850377542163679L;

	private RoomService roomService;
	
	protected List<String> filterTypes;			//过滤的类型
	protected List<String> filterStatuses;		//过滤的状态
	protected List<String> filterUseStatuses;	//过滤的状态
	protected List<String> filterLiveStatuses;	//过滤的状态
	protected List<String> filterRepairStatuses;//过滤的状态
	protected String filterFloor;				//楼层过滤
	
	private boolean splitByFloor;		//按楼层分割
	private boolean hideOrNone;			//被过滤掉的房间是否占位
	private int lineCapacity = 10;
	private boolean multiple;
	
	private List<RoomView> all;
	private HashSet<String> selected;
	private RoomSelectedListener selectedListener;
	private Component emptyView;
	private int showFlags;
	private boolean selectable = true;
	
	private Map<String, Living> livingMap;
	private Map<String, Booking> bookingMap;
	
	public RoomHistogram() {
		addEventListener(Events.ON_CREATE, this);
//		addEventListener(Events.ON_SIZE, this);
		roomService = Services.getRoomService();
		filterTypes = new ArrayList<String>();
		filterStatuses = new ArrayList<String>();
		filterUseStatuses = new ArrayList<String>();
		filterLiveStatuses = new ArrayList<String>();
		filterRepairStatuses = new ArrayList<String>();
		hideOrNone = false;
		lineCapacity = 10;
		multiple = false;
		selected = new HashSet<String>();
		all = new ArrayList<RoomView>();
		showFlags = RoomView.SHOW_ALL;
	}
	
	/** 
	 * 用于根据时间过滤
	 * (需已按楼层排序)
	 *  */
	protected List<Room> getRooms() {
		return roomService.listAllRooms();		//应该是当前酒店的所有房间
	}

	@Override
	public void onEvent(Event event) throws Exception {
		if (Events.ON_CREATE.equals(event.getName()))
			onCreate();
	}

	private void onCreate() {
		setStyle("overflow:scroll;");
		refresh();
	}
	
	public void refresh() {
		//Log.startTimer();
		selected.clear();
		UIUtils.removeAllChildren(this);
		initRooms(getRooms());
		if (selectedListener != null) {
			selectedListener.onSelected(null, true);
		}
	//	Log.t();
	}
	
	public void refreshRoom(String roomId) {
		RoomView rv = getView(roomId);
		if (rv != null)
			rv.updateRoom();
	}
	
	private void initDatas() {
		if ((showFlags & RoomView.SHOW_LIVING) != 0) {
			this.livingMap = new HashMap<String, Living>();
			
			List<Living> livings = Services.getReceptionService().listCurrentBasicLivings();
			for (Living living : livings) {
//				this.livingMap.put(living.getRoom().getName(), living);
				this.livingMap.put(living.getRoomId(), living);
			}
		}
		if ((showFlags & RoomView.SHOW_BOOKING) != 0) {
			this.bookingMap = new HashMap<String, Booking>();
			List<Booking> bookings = Services.getReceptionService().listBookings(BookingStatus.ONGOING);
			for (Booking booking : bookings) {
				if (booking.getReserved() == 0)
					continue;
				Collection<BookingRoom> rooms = booking.getBookingRooms();
				if (rooms == null || rooms.isEmpty())
					continue;
				for (BookingRoom bookingRoom : rooms) {
					if (!BookingStatus.ONGOING.is(bookingRoom.getStatus()))
						continue;
					Room room = bookingRoom.getRoom();
					if (room == null)
						continue;
					this.bookingMap.put(room.getName(), booking);
				}
			}
		}
	}

	private void initRooms(List<Room> rooms) {
		all.clear();
		initDatas();
		//Log.t();
		if (rooms == null || rooms.isEmpty()) {
			if (emptyView != null) {
				setVisible(false);
				emptyView.setVisible(true);
			}
			return;
		}
		setVisible(true);
		if (emptyView != null)
			emptyView.setVisible(false);
		
		List<Component> children = new ArrayList<Component>();
		Hbox line = null;
		String floor = null;
		int index = 0;
		boolean hasVisibleItem = false;
		for (int i = 0, j = rooms.size(); i < j; i++) {
			Room room = rooms.get(i);
			boolean show = showRoom(room);
			if (!show && (!hideOrNone || !splitByFloor))
				continue;
			if (splitByFloor) {
				String currentFloor = room.getFloor();
				if (floor != null && !floor.equals(currentFloor)) {
					Div splitter = new Div();
					splitter.setStyle("width:100%;height:2px;padding:2px;background-color:#dddddd;");
					children.add(splitter);
//					appendChild(splitter);
					index = 0;
				}
				floor = currentFloor;
			}
			if (index % lineCapacity == 0) {
				if (line != null && !hasVisibleItem) {
					children.remove(line);
//					removeChild(line);
				}
				line = addLine();
				children.add(line);
				hasVisibleItem = false;
			}
			hasVisibleItem |= show;
			all.add(addRoom(line, room, !show));
			index ++;
		}
		Component last = null;
		for (int i = 0, j = children.size(); i < j; i++) {
			Component child = children.get(i);
			if (child instanceof Div && last instanceof Div)
				continue;
			try {
				appendChild(child);
				last = child;
			}catch (Throwable e) {
			}
		}
//		this.bookingMap = null;
//		this.livingMap = null;
	}
	
	public Map<String, Living> getLivingMap() {
		return livingMap;
	}
	public Map<String, Booking> getBookingMap() {
		return bookingMap;
	}
	
	private Hbox addLine() {
		Hbox line = new Hbox();
		line.setStyle("width:100%;padding-bottom:5px;margin:5px 5px;");
//		line.setAction("onmouseover:zk.addClass(this, 'line_focused'); onmouseout:zk.rmClass(this, 'line_focused');");
		line.appendChild(new Hbox());
//		appendChild(line);
		return line;
	}
	
	protected void addEventListener(RoomView rv) {
		
	}
	
	private RoomView addRoom(Hbox line, Room room, boolean hide) {
		RoomView view = RoomView.get(room, this);
		view.setSelectable(selectable);
		addEventListener(view);
		((Component)line.getChildren().get(0)).appendChild(view);
		if (hide)
			view.setStyle("visibility:hidden;" + view.getStyle());
		view.setContext("roomPopup");
		return view;
	}
	
	private boolean showRoom(Room room) {
		if ((filterTypes.isEmpty() || filterTypes.contains(room.getType().getId())) && 
				(filterStatuses.isEmpty() || RoomStatus.match(filterStatuses, room)) &&
				(filterUseStatuses.isEmpty() || filterUseStatuses.contains(room.getUseStatus())) &&
				(filterLiveStatuses.isEmpty() || filterLiveStatuses.contains(room.getLiveStatus())) &&
				(filterRepairStatuses.isEmpty() || filterRepairStatuses.contains(room.getRepairStatus())) &&
				(filterFloor == null || filterFloor.equals(room.getFloor())))
			return true;
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////
	
	@SuppressWarnings("unchecked")
	public void setFilterTypes(Listbox roomTypeListbox) {
		Set<Listitem> selected = roomTypeListbox.getSelectedItems();
		filterTypes.clear();
		for (Listitem listitem : selected) {
			filterTypes.add((String)listitem.getAttribute("roomTypeId"));
		}
		refresh();
	}
	
	@SuppressWarnings("unchecked")
	public void setFilterUseStatus(Listbox roomStatusListbox) {
		Set<Listitem> selected = roomStatusListbox.getSelectedItems();
		filterUseStatuses.clear();
		for (Listitem listitem : selected) {
			filterUseStatuses.add((String)listitem.getAttribute("useStatus"));
		}
		refresh();
	}
	
	@SuppressWarnings("unchecked")
	public void setFilterLiveStatus(Listbox roomStatusListbox) {
		Set<Listitem> selected = roomStatusListbox.getSelectedItems();
		filterUseStatuses.clear();
		for (Listitem listitem : selected) {
			filterUseStatuses.add((String)listitem.getAttribute("liveStatus"));
		}
		refresh();
	}
	
	@SuppressWarnings("unchecked")
	public void setFilterStatus(Listbox statusListbox) {
		Set<Listitem> selected = statusListbox.getSelectedItems();
		filterStatuses.clear();
		for (Listitem listitem : selected) {
			filterStatuses.add((String)listitem.getAttribute("status"));
		}
		refresh();
	}
	
	public void setSplitByFloor(String splitByFloor) {
		this.splitByFloor = "true".equals(splitByFloor);
	}
	public void setSplitByFloor2(boolean bool) {
		this.splitByFloor = bool;
		refresh();
	}
	public void setLineCapacity(int lineCapacity) {
		if (lineCapacity != this.lineCapacity && lineCapacity >= 1) {
			this.lineCapacity = lineCapacity;
//			Log.i(lineCapacity);
//			refresh();
		}
//		if (lineCapacity > 1) {
//		}
	}
	public void setShowFlags(int flags) {
		this.showFlags = flags;
	}
	public int getShowFlags() {
		return showFlags;
	}
	public void setSelectable(boolean selectable) {
		this.selectable = selectable;
	}
	public void setFilterFloor(String floor) {
		String f = StringUtils.defaultIfEmpty(floor, null);
//		Log.d(f);
		if (StringUtils.equals(f, filterFloor)) {
			return;
		} else {
			filterFloor = f;
			refresh();
		}
	}
	public void setFilterFloor(Listbox floorListbox) {
		Listitem item = floorListbox != null ? floorListbox.getSelectedItem() : null;
		if (item == null)
			setFilterFloor((String)null);
		else
			setFilterFloor((String)item.getAttribute("floor"));
	}
	
	public int getLineCapacity() {
		return lineCapacity;
	}
	
	//选择之前改变这个值, 重复改变些值可能会出错
	public void setMultiple(boolean multiple) {
		if (this.multiple == multiple)
			return;
		this.multiple = multiple;
		if (!multiple) {
			if (selected.size() <= 1)
				return;
			ArrayList<String> a = new ArrayList<String>();
			a.addAll(selected);
			for (int i = a.size() - 1; i > 1; i++) {
				for (Iterator<RoomView> RoomView = all.iterator(); RoomView.hasNext();) {
					RoomView rv = RoomView.next();
					if (rv != null && a.get(i).equals(rv.getRoomId())) {
						rv.setSelected(false);
						if (selectedListener != null) {
							selectedListener.onSelected(rv.getRoomId(), false);
						}
						break;
					}
				}
			}
			selected.clear();
			selected.add(a.get(0));
		}
	}
	
	public void setSelected(RoomView selectedView) {
		String roomId = selectedView.getRoomId();
		if (multiple) {
			if (selected.contains(roomId)) {
				selectedView.setSelected(false);
				selected.remove(roomId);
				if (selectedListener != null) {
					selectedListener.onSelected(roomId, false);
				}
			} else {
				selectedView.setSelected(true);
				selected.add(roomId);
				if (selectedListener != null) {
					selectedListener.onSelected(roomId, true);
				}
			}
		} else {
			String last = selected.isEmpty() ? null : selected.iterator().next();
			if (roomId.equals(last))
				return;
			if (last != null) {
				for (Iterator<RoomView> RoomView = all.iterator(); RoomView.hasNext();) {
					RoomView rv = RoomView.next();
					if (rv != null && last.equals(rv.getRoomId())) {
						rv.setSelected(false);
						if (selectedListener != null) {
							selectedListener.onSelected(rv.getRoomId(), false);
						}
						break;
					}
				}
			}
			selected.clear();
			selected.add(roomId);
			selectedView.setSelected(true);
			if (selectedListener != null) {
				selectedListener.onSelected(roomId, true);
			}
		}
//		Log.i();
	}
	
	public String getSelectedRoom() {
		if (multiple)
			throw new RuntimeException();
		return selected.isEmpty() ? null : selected.iterator().next();
	}
	
	public String getSelectedRoomName() {
		if (multiple)
			throw new RuntimeException();
		String roomId = selected.isEmpty() ? null : selected.iterator().next();
		RoomView view = roomId == null ? null : getView(roomId);
		return view == null ? null : view.getRoom().getName();
	}
	
	public List<String> getSelected() {
		ArrayList<String> arr = new ArrayList<String>();
		arr.addAll(selected);
		if (arr.size() > 1) {
			Collections.sort(arr);
		}
		return arr;
	}
	public List<Room> getSelectedRooms() {
		ArrayList<Room> arr = new ArrayList<Room>();
		for (String roomId : selected) {
			arr.add(roomService.getRoom(roomId));
		}
		return arr;
	}
	
	protected RoomView getView(String roomId) {
		for (Iterator<RoomView> RoomView = all.iterator(); RoomView.hasNext();) {
			RoomView rv = RoomView.next();
			if (rv != null && roomId.equals(rv.getRoomId())) {
				return rv;
			}
		}
		return null;
	}
	
//	public void showRoomDetail(RoomView view) {
//		Log.i();
//	}
	
	public void setSelectedListener(RoomSelectedListener selectedListener) {
		this.selectedListener = selectedListener;
	}
	
	public void setEmptyView(Component emptyView) {
		this.emptyView = emptyView;
	}
}
